package com.stylefeng.guns.modular.flagglory.websocket;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.stylefeng.guns.common.persistence.model.GloryUser;
import com.stylefeng.guns.modular.flagglory.service.IGloryUserService;
import com.stylefeng.guns.modular.flagglory.service.IQuestionService;
import com.stylefeng.guns.modular.flagglory.service.ISettingService;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;

import javax.websocket.OnOpen;
import javax.websocket.Session;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;


/**
 * Created by likun on 2018/2/9.
 */
@Component
public class BattleWebSocketPushHandler implements WebSocketHandler {
    @Autowired
    private IGloryUserService userService;
    @Autowired
    private IQuestionService questionService;
    @Autowired
    private ISettingService settingService;
    //所有的房间
    private static List<WebSocketSession> userList = new CopyOnWriteArrayList<>();
    //最大题目数量
    private static final int QUESTION_NUMBER = 5;
    //最大题目数量
    private static final int SINGLE_QUESTION = 1;
    /**
     * 响应状态码
     */
    //进入房间，返回双方房间id
    private static final int RETURN_ROOM = 1000;
    //双方进入房间，返回给房主
    private static final int RETURN_BEGIN = 1001;
    //获取题目信息，返回给双方
    private static final int RETURN_QUESTION_INFO = 1002;
    //获取题目信息（单题），返回给所有房间内的用户
    private static final int RETURN_SINGLE_QUESTION = 10021;

    //返回对方方选择的答案信息
    private static final int RETURN_ANSWER = 1003;
    //返回双方当前答题完毕
    private static final int RETURN_ANSWER_FINAL = 1004;
    //返回双方信息
    private static final int RETURN_USER_LIST_INFO = 1005;
    //开始比赛
    private static final int RETURN_BEGIN_GAME = 1006;

    /**
     * 请求状态码
     */
    //房主请求开战
    private static final int SEND_BEGIN = 2000;
    //获取题目信息
    private static final int SEND_GET_QUESTION = 2001;
    //发送个人选项、答题时间（如果超时，强行发送选项为空）
    private static final int SEND_ANSWER_INFO = 2002;
    //获取房间内所有用户的信息
    private static final int SEND_ROOM_USER_INFO = 2003;
    /**
     * 异常、中断状态码
     */
    private static final int ERROR_CODE = 5001;

    private static final int CLOSE_CODE = 5002;
    /**
     * 用户状态码
     */
    //房主状态码
    private static final String ROOM_OWNER = "owner";
    //对战人状态码
    private static final String ROOM_GUEST = "guest";
    //围观者状态码
    private static final String ROOM_VISITOR = "visitor";

    //房主请
    @Override
    public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
        System.out.println("id为" + webSocketSession.getId());
    }

    @Override
    public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) throws Exception {
        String jsonString = JSONObject.toJSONString(webSocketMessage);
        JSONObject sendMessage = JSONObject.parseObject(jsonString);
        JSONObject payload = sendMessage.getJSONObject("payload");
        Boolean clean = payload.getBoolean("clean");
        if (null != clean && clean) {
            userList = new CopyOnWriteArrayList<>();
            return;
        }
        Integer code = payload.getInteger("code");
        String openId = payload.getString("openId");

        //返回的数据
        //获取用户信息
        Map<String, Object> userAttribute = webSocketSession.getAttributes();
        if (null == code) {
            code = 0;
        }
        if (code.equals(SEND_BEGIN)) {
            String roomId = webSocketSession.getAttributes().get("roomId").toString();
            List<WebSocketSession> users = userList.stream().filter(user -> user.getAttributes()
                    .get("roomId").toString().equals(roomId)).collect(Collectors.toList());
            JSONObject data = new JSONObject();
            settingService.getQuestionSetting(data);
            for (WebSocketSession user : users) {
                sendMessageToUser(user, getResult(data, RETURN_BEGIN_GAME));
            }
        }else if(code.equals(RETURN_SINGLE_QUESTION)){
            JSONArray questionArray = questionService.getRandomQuestionArray(SINGLE_QUESTION);
            JSONObject question = questionArray.getJSONObject(0);
            String roomId = webSocketSession.getAttributes().get("roomId").toString();
            List<WebSocketSession> users = userList.stream().filter(user -> user.getAttributes()
                    .get("roomId").toString().equals(roomId)).collect(Collectors.toList());
            for (WebSocketSession user : users) {
                sendMessageToUser(user, getResult(question, RETURN_QUESTION_INFO));
            }
          /*Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                public void run() {
                }
            }, 3000);*/
            //发送一道题目
        }else if (code.equals(SEND_GET_QUESTION)) {
            //发送题目
            JSONArray questionArray = questionService.getRandomQuestionArray(QUESTION_NUMBER);
            JSONObject data = new JSONObject();
            data.put("questions", questionArray);
            settingService.getQuestionSetting(data);
            String roomId = webSocketSession.getAttributes().get("roomId").toString();
            List<WebSocketSession> users = userList.stream().filter(user -> user.getAttributes()
                    .get("roomId").toString().equals(roomId)).collect(Collectors.toList());
            for (WebSocketSession user : users) {
                sendMessageToUser(user, getResult(data, RETURN_QUESTION_INFO));
            }
        } else if (code.equals(SEND_ANSWER_INFO)) {
            //返回答案数据 答题时间等
            //获取对方答题时间
            Integer answerTime = payload.getInteger("answerTime");
            //获取对方选择答案
            Integer answer = payload.getInteger("answer");
            Integer questionId = payload.getInteger("questionId");
            String answerNum = payload.getString("answerNum");
            webSocketSession.getAttributes().put("answerNum", answerNum);
            JSONObject data = new JSONObject();
            data.put("questionId", questionId);
            data.put("answerTime", answerTime);
            data.put("answer", answer);
            //todo 需要存一波
            String roomId = webSocketSession.getAttributes().get("roomId").toString();
            String userStatus = userAttribute.get("userStatus").toString();
            if (userStatus.equals(ROOM_VISITOR)) {
                return;
            }
            List<WebSocketSession> users = null;
            if (userStatus.equals(ROOM_OWNER)) {
                users = userList.stream().filter(user -> user.getAttributes()
                        .get("roomId").toString().equals(roomId)
                        && !user.getAttributes().get("userStatus").toString().equals(ROOM_OWNER)).collect(Collectors.toList());

            } else if (userStatus.equals(ROOM_GUEST)) {
                users = userList.stream().filter(user -> user.getAttributes()
                        .get("roomId").toString().equals(roomId)
                        && !user.getAttributes().get("userStatus").toString().equals(ROOM_GUEST)).collect(Collectors.toList());
            }
            for (WebSocketSession user : users) {
                Object otherAnswer = user.getAttributes().get("answerNum");
                if (null != otherAnswer) {
                    if (otherAnswer.toString().equals(answerNum)) {
                        data.put("isFinal", true);
                        sendMessageToUser(webSocketSession, getResult(data, RETURN_ANSWER_FINAL));
                    }
                }
                sendMessageToUser(user, getResult(data, RETURN_ANSWER));
            }
        } else if (code.equals(SEND_ROOM_USER_INFO)) {
            //发送房间内所有用户信息
            String roomId = payload.getString("roomId");
            JSONObject data = new JSONObject();
            JSONArray resultUserList = new JSONArray();
            List<WebSocketSession> roomUsers = userList.stream().filter(user -> user.getAttributes()
                    .get("roomId").toString().equals(roomId)).collect(Collectors.toList());
            for (WebSocketSession roomUser : roomUsers) {
                Map<String, Object> attribute = roomUser.getAttributes();
                JSONObject userJson = JSONObject.parseObject(JSONObject.toJSONString(attribute.get("info")));
                userJson.put("userStatus", attribute.get("userStatus"));
                userJson.put("roomId", attribute.get("roomId"));
                userJson.put("sessionUserId", roomUser.getId());
                resultUserList.add(userJson);
            }
            data.put("resultUserList", resultUserList);
            for (WebSocketSession roomUser : roomUsers) {
                data.put("sessionUserId", roomUser.getId());
                data.put("userStatus", roomUser.getAttributes().get("userStatus"));
                sendMessageToUser(roomUser, getResult(data, RETURN_USER_LIST_INFO));
            }
        } else {
            String roomId = payload.getString("roomId");
            //如果未触发任何code，就进入指定的房间
            addUserList(webSocketSession, openId, roomId);
            //roomId不为空就进入该房间
            if (StringUtils.isNotBlank(roomId)) {
                //获取到同一个房间的所有用户
                List<WebSocketSession> roomUsers = userList.stream().filter(user -> null != user.getAttributes().get("roomId")
                        && user.getAttributes().get("roomId").toString().equals(roomId)).collect(Collectors.toList());
                if (roomUsers.size() > 0) {
                    //查找房主
                    List<WebSocketSession> roomOwners = roomUsers.stream().filter(user -> null != user.getAttributes().get("userStatus")
                            && user.getAttributes().get("userStatus").toString().equals(ROOM_OWNER)
                            && !user.getId().equals(webSocketSession.getId())).collect(Collectors.toList());
                    //如果有房主，设置为对战人，否则设置为房主。
                    if (roomOwners.size() > 0) {
                        List<WebSocketSession> roomGuest = roomUsers.stream().filter(user -> null != user.getAttributes().get("userStatus")
                                && user.getAttributes().get("userStatus").toString().equals(ROOM_GUEST)
                                && !user.getId().equals(webSocketSession.getId())).collect(Collectors.toList());
                        if (roomGuest.size() <= 0) {
                            //没有对战者就添加对战者
                            userAttribute.put("userStatus", ROOM_GUEST);
                        } else {
                            //添加观战者
                            userAttribute.put("userStatus", ROOM_VISITOR);
                            return;
                        }
                        //返回可以开始对战的状态码
                        JSONObject data = new JSONObject();
                        JSONArray resultUserList = new JSONArray();
                        //返回给房间所有人该房间用户信息
                        for (WebSocketSession roomUser : roomUsers) {
                            Map<String, Object> attribute = roomUser.getAttributes();
                            JSONObject userJson = JSONObject.parseObject(JSONObject.toJSONString(attribute.get("info")));
                            userJson.put("userStatus", attribute.get("userStatus"));
                            userJson.put("roomId", attribute.get("roomId"));
                            userJson.put("sessionUserId", roomUser.getId());
                            resultUserList.add(userJson);
                        }
                        data.put("resultUserList", resultUserList);
                        for (WebSocketSession roomUser : roomUsers) {
                            data.put("sessionUserId", roomUser.getId());
                            data.put("userStatus", roomUser.getAttributes().get("userStatus"));
                            sendMessageToUser(roomUser, getResult(data, RETURN_BEGIN));
                        }
                    } else {
                        //没有房主直接成为房主
                        userAttribute.put("userStatus", ROOM_OWNER);
                    }
                } else {
                    //房间没有人直接成为房主
                    userAttribute.put("userStatus", ROOM_OWNER);
                }
                userAttribute.put("roomId", roomId);
                //
            } else {
                //roomId如果为空就创建新房间
                String generateRoomId = generateRoomId();
                userAttribute.put("roomId", generateRoomId);
                userAttribute.put("userStatus", ROOM_OWNER);
            }
            //返回房间id信息
            JSONObject roomJson = new JSONObject();
            roomJson.put("roomId", webSocketSession.getAttributes().get("roomId"));
            roomJson.put("userInfo", webSocketSession.getAttributes().get("info"));
            roomJson.put("userStatus", webSocketSession.getAttributes().get("userStatus"));
            sendMessageToUser(webSocketSession, getResult(roomJson, RETURN_ROOM));
        }
    }

    private void addUserList(WebSocketSession webSocketSession, String openId, String roomId) {
        boolean flag = true;
        for (WebSocketSession user : userList) {
            if (user.getId().equals(webSocketSession.getId())) {
                //每次都给一下roomId,防止roomId更换
                if (StringUtils.isNotBlank(roomId)) {
                    user.getAttributes().put("roomId", roomId);
                }
                flag = false;
                break;
            }
        }
        if (flag) {
            //如果没有添加session就添加
            //添加用户基本信息
            Map<String, Object> info = userService.selectGloryUserInfo(openId);
            webSocketSession.getAttributes().put("info", info);
            if (StringUtils.isNotBlank(roomId)) {
                webSocketSession.getAttributes().put("roomId", roomId);
            }
            //一定要最后再添加
            userList.add(webSocketSession);
        }
    }

    @Override
    public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {
        //需要做异常的提示
        Object roomIdObj = webSocketSession.getAttributes().get("roomId");
        if (null != roomIdObj) {
            //如果退出的是房主，就更换房主
            if (webSocketSession.getAttributes().get("userStatus").toString().equals(ROOM_OWNER)) {
                List<WebSocketSession> users = userList.stream().filter(user -> user.getAttributes()
                        .get("userStatus").toString().equals(ROOM_GUEST)).collect(Collectors.toList());
                if (users.size() >= 1) {
                    users.get(0).getAttributes().put("userStatus", ROOM_OWNER);
                }
            }
            userList.remove(webSocketSession);
            String roomId = roomIdObj.toString();
            List<WebSocketSession> users = userList.stream().filter(user -> user.getAttributes()
                    .get("roomId").toString().equals(roomId)).collect(Collectors.toList());
            String userStatus = webSocketSession.getAttributes().get("userStatus").toString();
            JSONObject data = new JSONObject();
            data.put("userStatus", userStatus);
            for (WebSocketSession user : users) {
                sendMessageToUser(user, getResult(data, ERROR_CODE));
            }
        }
        if (webSocketSession.isOpen()) {
            webSocketSession.close();
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
        Object roomIdObj = webSocketSession.getAttributes().get("roomId");
        if (null != roomIdObj) {
            //如果退出的是房主，就更换房主
            if (webSocketSession.getAttributes().get("userStatus").toString().equals(ROOM_OWNER)) {
                List<WebSocketSession> users = userList.stream().filter(user -> user.getAttributes()
                        .get("userStatus").toString().equals(ROOM_GUEST)).collect(Collectors.toList());
                if (users.size() >= 1) {
                    users.get(0).getAttributes().put("userStatus", ROOM_OWNER);
                }
            }
            userList.remove(webSocketSession);
            if (userList.size() < 1) {
                return;
            }
            String roomId = roomIdObj.toString();
            List<WebSocketSession> users = userList.stream().filter(user -> user.getAttributes()
                    .get("roomId").toString().equals(roomId)).collect(Collectors.toList());
            String userStatus = webSocketSession.getAttributes().get("userStatus").toString();
            JSONObject data = new JSONObject();
            data.put("userStatus", userStatus);
            data.put("info", webSocketSession.getAttributes().get("info"));
            for (WebSocketSession user : users) {
                sendMessageToUser(user, getResult(data, CLOSE_CODE));
            }
        }
        if (webSocketSession.isOpen()) {
            webSocketSession.close();
        }
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }

    /**
     * 给所有的用户发送消息
     */
    public void sendMessagesToUsers(TextMessage message) {
      /*  for (WebSocketSession user : users) {
            try {
                // isOpen()在线就发送
                if (user.isOpen()) {
                    user.sendMessage(message);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }*/
    }


    public void sendMessageToUser(WebSocketSession user, TextMessage message) {
        if (user.isOpen()) {
            try {
                user.sendMessage(message);
            } catch (IOException e) {

            }
        }
    }

    //生成房间id
    private String generateRoomId() {
        return UUID.randomUUID().toString();
    }

    //封装返回信息
    private TextMessage getResult(JSONObject data, int returnCode) {
        if (null == data) {
            data = new JSONObject();
        }
        data.put("returnCode", returnCode);
        JSONObject result = new JSONObject();
        result.put("data", data);
        result.put("code", 200);
        return new TextMessage(result.toJSONString());
    }
}
